package heap

func (k *Class) IsArray() bool {
	return k.name[0] == '['
}

func (k *Class) ArrayClass() *Class {
	arrayClassName := getArrayClassName(k.name)
	return k.loader.LoadClass(arrayClassName)
}

func (k *Class) ComponentClass() *Class {
	componentClassName := getComponentClassName(k.name)
	return k.loader.LoadClass(componentClassName)
}

func getComponentClassName(name string) string {
	if name[0] == '[' {
		componentTypeDescriptor := name[1:]
		return toClassName(componentTypeDescriptor)
	}
	panic("Not Array：" + name)
}

func toClassName(descriptor string) string {
	if descriptor[0] == '[' {
		return descriptor
	}
	if descriptor[0] == 'L' {
		return descriptor[1 : len(descriptor)-1]
	}
	for className, d := range primitiveTypes {
		if d == descriptor {
			return className
		}
	}
	panic("Invalid descriptor: " + descriptor)
}

func (k *Class) NewArray(count uint) *Object {
	if !k.IsArray() {
		panic("Not Array Class: " + k.name)
	}
	switch k.Name() {
	case "[Z":
		return &Object{k, make([]int8, count), nil}
	case "[B":
		return &Object{k, make([]int8, count), nil}
	case "[C":
		return &Object{k, make([]uint16, count), nil}
	case "[S":
		return &Object{k, make([]int16, count), nil}
	case "[I":
		return &Object{k, make([]int32, count), nil}
	case "[J":
		return &Object{k, make([]int64, count), nil}
	case "[F":
		return &Object{k, make([]float32, count), nil}
	case "[D":
		return &Object{k, make([]float64, count), nil}
	default:
		return &Object{k, make([]*Object, count), nil}
	}
}

func NewByteArray(loader *ClassLoader, bytes []int8) *Object {
	return &Object{loader.LoadClass("[B"), bytes, nil}
}
